#include "cpu/exec/template-start.h"
#include "memory/tlb.h"
#define instr mov

static void do_execute() {
	OPERAND_W(op_dest, op_src->val);
	print_asm_template2();
}

make_instr_helper(i2r)
make_instr_helper(i2rm)
make_instr_helper(r2rm)
make_instr_helper(rm2r)

make_helper(concat(mov_a2moffs_, SUFFIX)) {
	swaddr_t addr = instr_fetch(eip + 1, 4);
	MEM_W(addr, REG(R_EAX), R_DS);

	print_asm("mov" str(SUFFIX) " %%%s,0x%x", REG_NAME(R_EAX), addr);
	return 5;
}

make_helper(concat(mov_moffs2a_, SUFFIX)) {
	swaddr_t addr = instr_fetch(eip + 1, 4);
	REG(R_EAX) = MEM_R(addr, R_DS);

	print_asm("mov" str(SUFFIX) " 0x%x,%%%s", addr, REG_NAME(R_EAX));
	return 5;
}

#if DATA_BYTE == 2
static void load_sreg(uint8_t sreg_no) {
	//get the index of the segment descriptor
    uint16_t index = cpu.reg[sreg_no].selector >> 3;
	//get the segment descriptor
	Seg_des->part1.val1 = lnaddr_read(cpu.gdtr.base + (index << 3), 4);
	Seg_des->part2.val2 = lnaddr_read(cpu.gdtr.base + (index << 3) + 4, 4);
	//get the base and limit of the segment descriptor
	cpu.reg[sreg_no].base = (uint32_t)Seg_des ->part1.base1 
						  + ((uint32_t)Seg_des->part2.base2 << 16) 
						  + ((uint32_t)Seg_des->part2.base3 << 24);
	//get the limit of the segment descriptor
	cpu.reg[sreg_no].limit = ((uint32_t)Seg_des->part1.limit1) 
						   + ((uint32_t)Seg_des->part2.limit2 << 16)
						   + (((uint32_t)0xfff) << 24);
	
	if(Seg_des->part2.g == 1) {
		cpu.reg[sreg_no].limit <<= 12;
	}
}

make_helper(mov_rm2sreg){
    uint8_t modrm = instr_fetch(eip+1, 1);
    uint8_t sreg_no = (modrm >> 3) & 0x7;
    uint8_t srcreg = (modrm & 0x7);
	//get the segment descriptor
    cpu.reg[sreg_no].selector = REG(srcreg);
	load_sreg(sreg_no);

    return 2;
}
#endif

#if DATA_BYTE == 4
	make_helper(mov_r2cr){
		int len=decode_rm2r_l(eip+1);
		if(op_dest->reg==0) {
			cpu.cr0.val=op_src->val;
		} else if(op_dest->reg==3) {
			cpu.cr3.val=op_src->val;
			init_tlb();
		}
		print_asm_template2();
		return 1+len;
	}

	make_helper(mov_cr2r){
		int len=decode_rm2r_l(eip+1);
		if(op_dest -> reg == 0) {
		  	OPERAND_W(op_src,cpu.cr0.val);
		} else if(op_dest -> reg == 3) {
		  	OPERAND_W(op_src,cpu.cr3.val);
		}
		print_asm_template2();
		return 1+len;
	}
#endif

#include "cpu/exec/template-end.h"
